package com.jerei.web.plugin.controller;

import com.jerei.utils.UtilsBean;
import com.jerei.utils.spring.IEntity;
import com.jerei.web.plugin.api.IController;
import com.jerei.web.utils.UtilsUI;
import com.jerei.web.utils.UtilsWeb;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.ui.Model;
import ro.fortsoft.pf4j.Plugin;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * Created by sunfeihu on 2016/11/28.
 */
public class PluginController implements IController {

    private HttpServletRequest request;
    private HttpServletResponse response;
    private Plugin plugin;
    private Model model;
    private Set<String> methodSet;

    protected <T> T wrapper(Class<T> clzz) {
        T entity = UtilsBean.wrapper(clzz, this.getRequest().getParameterMap());
        if (entity instanceof IEntity) {
            IEntity e = (IEntity) entity;
            if (null == e.getId() || e.getId().equals(0L)) {
                e.setAddDate(Calendar.getInstance().getTime());
                e.setUuid(UUID.randomUUID().toString());
                e.setAddIp(UtilsWeb.getIp(this.getRequest()));
                e.setAddUser("");
            }
            e.setUpdateDate(Calendar.getInstance().getTime());
            e.setUpdateIp(UtilsWeb.getIp(this.getRequest()));
            e.setAddUser("");
        }
        return entity;
    }

    @Override
    public Boolean haveMethod(String op) {
        if (null == methodSet) {
            methodSet = new HashSet<String>();
            Method[] methods = this.getClass().getDeclaredMethods();
            if (null != methods && methods.length > 0) {
                for (Method method : methods) {
                    methodSet.add(method.getName());
                }
            }
        }
        return this.methodSet.contains(op);
    }

    @Override
    public Object get(HttpServletRequest request, HttpServletResponse response, Model model, String op, Plugin plugin) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        String pluginPath = "/admin/plugins" + plugin.getWrapper().getPluginPath() + "/classes";
        this.request = request;
        this.response = response;
        this.plugin = plugin;
        this.model = model;
        Method method = this.getClass().getMethod(op);
        //取出权限注解
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
        //如果没有权限注解，抛出没有权限异常
        if (null == requiresPermissions) {
            throw new AuthorizationException();
        }
        String[] perms = requiresPermissions.value();
        //如果权限表达式为空，抛出没有权限异常
        if (null == perms || perms.length <= 0) {
            throw new AuthorizationException();
        }
        Subject subject = SecurityUtils.getSubject();
        //如果没有权限，抛出没有权限异常
        if (!subject.isPermittedAll(perms)) {
            throw new AuthorizationException("没有权限");
        }
        Object returnVal = MethodUtils.invokeExactMethod(this, op);
        //如果是void，直接返回请求路径
        if (method.getReturnType().equals(Void.TYPE)) {
            return pluginPath + "/" + op;
        }
        return returnVal;
    }

    @Override
    public Object post(HttpServletRequest request, HttpServletResponse response, Model model, String op, Plugin plugin) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        String pluginPath = "/admin/plugins" + plugin.getWrapper().getPluginPath() + "/classes";
        model.addAttribute("pluginPath", pluginPath);
        this.request = request;
        this.response = response;
        this.plugin = plugin;
        this.model = model;
        Method method = this.getClass().getMethod(op);
        //取出权限注解
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
        //如果没有权限注解，抛出没有权限异常
        if (null == requiresPermissions) {
            throw new AuthorizationException("没有权限");
        }
        String[] perms = requiresPermissions.value();
        //如果权限表达式为空，抛出没有权限异常
        if (null == perms || perms.length <= 0) {
            throw new AuthorizationException();
        }
        Subject subject = SecurityUtils.getSubject();
        //如果没有权限，抛出没有权限异常
        if (!subject.isPermittedAll(perms)) {
            throw new AuthorizationException();
        }
        Object returnVal = MethodUtils.invokeExactMethod(this, op);
        //如果是void，直接返回请求路径
        if (method.getReturnType().equals(Void.TYPE)) {
            return UtilsUI.ok();
        }
        return returnVal;
    }

    public HttpServletRequest getRequest() {
        return request;
    }

    public HttpServletResponse getResponse() {
        return response;
    }

    public Plugin getPlugin() {
        return plugin;
    }

    public Model getModel() {
        return model;
    }
}
